/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pa165.bookingmanager.web;

import cz.muni.fi.pa165.bookingmanager.adapters.AdministratorAdapter;
import cz.muni.fi.pa165.bookingmanager.dto.AdminRoleDTO;
import cz.muni.fi.pa165.bookingmanager.dto.AdministratorDTO;
import cz.muni.fi.pa165.bookingmanager.entities.AdminRole;
import cz.muni.fi.pa165.bookingmanager.exceptions.IllegalOrphanException;
import cz.muni.fi.pa165.bookingmanager.exceptions.NonexistentEntityException;
import cz.muni.fi.pa165.bookingmanager.exceptions.PreexistingEntityException;
import cz.muni.fi.pa165.bookingmanager.other.Roles;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.logging.Level;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.SimpleError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Radek Koubsky
 */
@UrlBinding("/admin/administrator/{$event}")
public class AdministratorActionBean extends MyActionBean {

    final static Logger log = LoggerFactory.getLogger(AdministratorActionBean.class);
    private AdministratorAdapter administratorAdapter;
        
    private List<AdministratorDTO> list = new ArrayList<AdministratorDTO>();
    @ValidateNestedProperties(value = {
        @Validate(on = {"add", "save"}, field = "firstName", required = true),
        @Validate(on = {"add", "save"}, field = "surName", required = true),
        @Validate(on = {"add", "save"}, field = "username", required = true),
        @Validate(on = {"add", "save"}, field = "password", required = true)
        
    })
    private AdministratorDTO administrator;    
    private String administratorName;
    
    private Roles role;

    public AdministratorActionBean() throws NamingException {
        Context ctx = new InitialContext();
        this.administratorAdapter = (AdministratorAdapter) ctx.lookup("java:global/cz.muni.fi.pa165.bookingmanager_booking_manager-web_war_1.0-SNAPSHOT/AdministratorAdapterImpl!cz.muni.fi.pa165.bookingmanager.adapters.AdministratorAdapter");
        
        list = getAdministrators();
    }

    public Roles getRole() {
        return role;
    }

    public void setRole(Roles role) {
        this.role = role;
    }

    

    

    @DefaultHandler
    public Resolution all() {
        log.debug("all()");
        return new ForwardResolution("/backend/administrators/list.jsp");
    }    

    public Resolution add() throws IllegalOrphanException, Exception {
        administrator.setPassword(calcHash(administrator.getPassword()));
        log.debug("add() administrator={}", administrator); 
        
        setRoles(role);
        try{
        if("admin".equals(administrator.getUsername()))
        {
            throw new PreexistingEntityException(null);
        }
        
        administratorAdapter.createAdministrator(administrator);
        }
        catch(PreexistingEntityException ex)
        {   Locale currentLocale = new Locale("cs");
            getContext().getValidationErrors().addGlobalError(new LocalizableError("preexisting.user"));
            getContext().getSourcePageResolution().execute(getContext().getRequest(),getContext().getResponse());
        }
        return new RedirectResolution(this.getClass(), "all");
    }
    
    private void setRoles(Roles role)
    {
        List<AdminRoleDTO> roles = new ArrayList<AdminRoleDTO>();
        switch(role)
        {
            case RECEPTIONIST:
                AdminRoleDTO admin = new AdminRoleDTO();
                admin.setPermission(Roles.RECEPTIONIST);
                
                roles.add(admin);
                break;
            case ADMIN:
                AdminRoleDTO admin2 = new AdminRoleDTO();
                admin2.setPermission(Roles.RECEPTIONIST);
                roles.add(admin2);
                AdminRoleDTO admin3 = new AdminRoleDTO();
                admin3.setPermission(Roles.ADMIN);
                roles.add(admin3);
                break;
                    
                        
                    
            
        }
         administrator.setRoles(roles);
        
    }
    public AdministratorDTO getAdministrator() {
        return administrator;
    }

    public void setAdministrator(AdministratorDTO administrator) {
        this.administrator = administrator;
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"edit", "save", "delete"})
    public void loadAdministratorFromDatabase() {
        String ids = getContext().getRequest().getParameter("administrator.id");
        if (ids == null) {
            return;
        }
        administrator = administratorAdapter.getAdministratorById(Long.parseLong(ids));
    }

    public Resolution edit() {
        //administrator.setPassword(calcHash(administrator.getPassword()));
        log.debug("edit() administrator={}", administrator);
        return new ForwardResolution("/backend/administrators/edit.jsp");
    }

    public Resolution save() throws NonexistentEntityException, IllegalOrphanException, PreexistingEntityException, Exception {
        administrator.setPassword(calcHash(administrator.getPassword()));
        log.debug("save() administrator={}", administrator);
        setRoles(role);
        try{
        if("admin".equals(administrator.getUsername()))
        {
            throw new PreexistingEntityException(null);
        }
        
        administratorAdapter.updateAdministrator(administrator);
        }
        catch(PreexistingEntityException ex)
        {   Locale currentLocale = new Locale("cs");
            getContext().getValidationErrors().addGlobalError(new LocalizableError("preexisting.user"));
            getContext().getSourcePageResolution().execute(getContext().getRequest(),getContext().getResponse());
        }
        return new RedirectResolution(this.getClass(), "all");
    }

    public Resolution delete() throws NonexistentEntityException, IllegalOrphanException {
        log.debug("delete({})", administrator.getId());
        
        administratorAdapter.deleteAdministrator(administrator);
        return new RedirectResolution(this.getClass(), "all");
    }

    public String getAdministratorName() {
        return administratorName;
    }

    public void setAdministratorName(String administratorName) {
        this.administratorName = administratorName;
    }

    public List<AdministratorDTO> getList() {
        if (this.list == null) {
            return null;
        }
        return Collections.unmodifiableList(list);
    }

    public void setList(List<AdministratorDTO> list) {
        this.list = new ArrayList<AdministratorDTO>();
        this.list.addAll(list);
    }
    
    public List<AdministratorDTO> getAdministrators() {
        return administratorAdapter.findAllAdministrators();
    }
    
    private String calcHash(String password){ 
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException ex) {
            log.debug(ex.getMessage());
            return "0";
        }
        
        md.update(password.getBytes());
 
        byte hash[] = md.digest();
 
        //convert the byte to hex format method 1
        StringBuilder sb = new StringBuilder();
        for(byte b : hash) {
            if (b > 0 && b < 16) {
                sb.append("0");
            }
            sb.append(Integer.toHexString(b & 0xff));
        }
 
        return sb.toString();
        
    }
}
